﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Nyx.Scenes
{
    /// <summary>
    /// A 2D camera capable of panning, zooming, and rotating.
    /// </summary>
    public class Camera2D
    {
        Vector2 position;
        float rotation;
        float scale = 1f;
        Matrix transform = Matrix.Identity;
        bool transformDirty;

        /// <summary>
        /// The default scale value.
        /// </summary>
        public const float DefaultScale = 1f; // 100%
        
        /// <summary>
        /// The minimum scale value.
        /// </summary>
        public const float MinScale = .1f; // 10%

        /// <summary>
        /// The maximum scale value.
        /// </summary>
        public const float MaxScale = 10f; // 1000%

        /// <summary>
        /// The value by which scale will increase or decrease when changed.
        /// </summary>
        public const float ScaleStep = .1f; // 10%

        /// <summary>
        /// Initializes a new instance of the <see cref="Camera2D"/> class.
        /// </summary>
        public Camera2D()
        {
        }

        /// <summary>
        /// Gets or sets the position.
        /// </summary>
        /// <value>The position.</value>
        public Vector2 Position
        {
            get { return position; }
            set
            {
                if (position != value)
                {
                    position = value;
                    transformDirty = true;
                }
            }
        }

        /// <summary>
        /// Gets or sets the rotation.
        /// </summary>
        /// <value>The rotation.</value>
        public float Rotation
        {
            get { return rotation; }
            set
            {
                if (rotation != value)
                {
                    rotation = value % MathHelper.TwoPi;
                    transformDirty = true;
                }
            }
        }

        /// <summary>
        /// Gets or sets the scale.
        /// </summary>
        /// <value>The scale.</value>
        public float Scale
        {
            get { return scale;}
            set
            {
                if (scale != value)
                {
                    scale = Math.Min(Math.Max(value, MinScale), MaxScale);
                    transformDirty = true;
                }
            }
        }

        /// <summary>
        /// Gets the transform.
        /// </summary>
        /// <value>The transform.</value>
        public Matrix Transform
        {
            get
            {
                if (transformDirty)
                {
                    transform = Matrix.CreateScale(scale) *
                        Matrix.CreateRotationZ(rotation) *
                        Matrix.CreateTranslation(new Vector3(position, 0f));
                    transformDirty = false;
                }
                return transform;
            }
        }

        /// <summary>
        /// Centers the camera on the specified scene.
        /// </summary>
        /// <param name="graphicsDevice">The graphics device rendering the scene.</param>
        /// <param name="scene">The scene.</param>
        public void CenterOnScene(GraphicsDevice graphicsDevice, Scene scene)
        {
            this.Position = new Vector2((graphicsDevice.Viewport.Width - scene.Width) / 2f, (graphicsDevice.Viewport.Height - scene.Height) / 2f);
        }
    }
}
